/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2022-2023. All rights reserved.
 */

package controllers

import (
	"encoding/json"
	"prim-server/common"
	"prim-server/errcode"
	"prim-server/primservice/validator"
	fundService "prim-server/service/fund"
	payService "prim-server/service/pay"
	userService "prim-server/service/user"
	websocketService "prim-server/service/websocket"
	"prim-server/util"
	"time"

	"github.com/gorilla/websocket"
	"github.com/pkg/errors"
	"github.com/spf13/cast"
)

const (
	//balance recharge just for user
	BalanceRechargeURL        = "/v1/user/balance/recharge"
	QueryUserBalanceURL       = "/v1/user/balance/query"
	QueryUserBalanceRecordURL = "/v1/user/balance/changeRecord"
	QueryUserCreditURL        = "/v1/user/credit/query"

	//admin Test interface -- no register router
	QueryCloudCreditURL       = "/v1/partner/credit/query"
	AdjustCloudCreditURL      = "/v1/partner/credit/adjust"
	QueryCloudCreditRecordURL = "/v1/partner/credit/record"
)

type FundController struct {
	CommonController
}

// 充值--websocket--普通用户
func (fc *FundController) BalanceRecharge() {
	//websocket和其他http请求检验规则不能使用session，单独校验
	claimId, err := fc.GetUserIdFromToken()
	if err != nil {
		fc.HandleErrCode(errcode.E.Base.RequestInvalid.WithMessage("非法请求"))
		return
	}
	if !websocketService.IsWebSocket(fc.Ctx.Request) {
		fc.HandleErrCode(errcode.E.Base.RequestInvalid.WithMessage("非法请求"))
		return
	}
	conn, err := websocketService.BuildWebSocket(fc.Ctx.ResponseWriter, fc.Ctx.Request)
	if err != nil {
		return
	}
	defer conn.Close()
	for {
		_, msg, err := websocketService.ReadMessageFromWebSocket(conn)
		//感知到链接断开
		if err != nil {
			break
		}
		req, cloudUserId, err := fc.getAndcheckBalanceRechargeRequest(claimId, msg, conn)
		if err != nil {
			continue
		}
		// build balance record
		balanceRecord, err := fundService.CreateAndSaveDefaultBalianceRecordForCharge(req.UserId, cloudUserId, req.PaymentMethod, req.PaymentAmount)
		if err != nil {
			websocketService.WriteMessageIntoWebSocket([]byte(err.Error()), conn)
			return
		}
		// 1.返回二维码订单给前端
		codeUrl := "weixin://wxpay/bizpayurl/up?pr=NwY5Mz9&groupid=00"
		codeResponse := common.PaymentInfo{CodeUrl: codeUrl}
		codeByte, err := json.Marshal(codeResponse)
		if err != nil {
			err = errors.New("生成二维码参数错误")
			websocketService.WriteMessageIntoWebSocket([]byte(err.Error()), conn)
			break
		}
		if err = websocketService.WriteMessageIntoWebSocket(codeByte, conn); err != nil {
			websocketService.WriteMessageIntoWebSocket([]byte(err.Error()), conn)
			break
		}
		// 2.等待用户支付--用户扫微信
		// 3.等待异步接受第三方支付结果通知--/v1/pa	yment/notify
		/////////////////////////////////////////////////////////
		//模拟通知系统第三方订单状态已经修改--该部分需要在/v1/payment/notify中完成
		paymentMessage := &util.PaymentMessage{
			RecordId:     balanceRecord.BalanceRecordId,
			RecordStatus: util.GetPaymentStatusOfCompleted(),
		}
		payService.WriteIntoMessage(paymentMessage.RecordId, paymentMessage)
		fc.dealWithPayment(balanceRecord.BalanceRecordId, cloudUserId, req, conn)
		return
	}
}

// 读取并检查充值信息
func (fc *FundController) getAndcheckBalanceRechargeRequest(claimId string, msg []byte, conn *websocket.Conn) (req common.BalanceRechargeRequest, cloudUserId string, err error) {
	//读取充值信息
	req = common.BalanceRechargeRequest{}
	if err = json.Unmarshal(msg, &req); err != nil {
		err = errors.New("参数解析错误")
		websocketService.WriteMessageIntoWebSocket([]byte(err.Error()), conn)
		return req, "", err
	}
	if err = validator.Validate(&req); err != nil {
		fc.HandleErrCode(errcode.E.Base.RequestInvalid.WithErr(err))
		return
	}
	//参数检查
	if err = fc.CheckRequestParamentForBalanceRecharge(req, claimId); err != nil {
		websocketService.WriteMessageIntoWebSocket([]byte(err.Error()), conn)
		return req, "", err
	}
	//查找云上账户ID
	cloudUser, err := userService.GetCloudUserOne(req.UserId)
	if err != nil {
		websocketService.WriteMessageIntoWebSocket([]byte(err.Error()), conn)
		return req, "", err
	}
	if cloudUser == nil {
		err = errors.New("clouduser can't be found")
		websocketService.WriteMessageIntoWebSocket([]byte(err.Error()), conn)
		return req, "", err
	}
	return req, cloudUser.CloudId, nil
}

// 处理支付结果
func (fc *FundController) dealWithPayment(balanceRecordId, cloudUserId string, req common.BalanceRechargeRequest, conn *websocket.Conn) {
	retMessage := ""
	for {
		time.Sleep(3 * time.Second)
		//检查第三方支付结果通知
		webMsg, err := payService.ReadFromMessage(balanceRecordId)
		if err != nil {
			continue
		}
		//支付成功处理
		if util.IsPayCompleted(webMsg.RecordStatus) {
			//1.增加云上账户额度
			err = fundService.AjudstCloudCreditForIncrease(cloudUserId, req.PaymentAmount)
			if err != nil {
				retMessage += "\n额度调整失败:" + err.Error()
				responseData := fc.BuildFailResponse(errcode.E.Internal.Internal.WithMessage(retMessage))
				_ = websocketService.WriteMessageIntoWebSocket(responseData, conn)
				continue
			}
			//2.更新账户余额
			err = fundService.UpdateAcountAndRecordForChargeCompleted(req.UserId, cloudUserId, &req.PaymentAmount, req.PaymentMethod, req.CouponId, balanceRecordId)
			if err != nil {
				retMessage += "\n更新账户失败" + err.Error()
				responseData := fc.BuildFailResponse(errcode.E.Internal.Internal.WithMessage(retMessage))
				_ = websocketService.WriteMessageIntoWebSocket(responseData, conn)
				continue
			}
			responseData := fc.BuildSuccessResponse()
			_ = websocketService.WriteMessageIntoWebSocket(responseData, conn)
			break
		}
		//支付失败处理
		if util.IsPayFail(webMsg.RecordStatus) {
			retMessage += "支付失败"
			responseData := fc.BuildFailResponse(errcode.E.Internal.Internal.WithMessage(retMessage))
			_ = websocketService.WriteMessageIntoWebSocket(responseData, conn)
			//do something
			break
		}
		//支付中--继续轮询
		if util.IsPaying(webMsg.RecordStatus) {
			retMessage += "支付中"
			responseData := fc.BuildFailResponse(errcode.E.Internal.Internal.WithMessage(retMessage))
			_ = websocketService.WriteMessageIntoWebSocket(responseData, conn)
			continue
		}
	}
}

// 用于用户充值的参数检查
func (fc *FundController) CheckRequestParamentForBalanceRecharge(req common.BalanceRechargeRequest, claimId string) error {
	user, err := userService.GetUserById(req.UserId)
	if err != nil || user == nil {
		return errors.New("用户不存在")
	}
	if !user.Authenticated {
		return errors.New("用户未实名认证")
	}
	admin, err := userService.GetAdminId()
	if err != nil || admin == req.UserId {
		return errors.New("非法请求")
	}
	//请求的userId和token中的userId不一致
	if req.UserId != claimId {
		return errors.New("非法请求")
	}
	if !util.ValidatePaymentMethod(req.PaymentMethod) {
		return errors.New("不支持的支付方式")
	}
	if fundService.CheckAmountZero(req.PaymentAmount) {
		return errors.New("充值金额必须大于等于0.01")
	}
	return nil
}

// 查询用户账户余额
func (fc *FundController) BalanceQuery() {
	userId := fc.Ctx.Input.Query("userId")
	//校验是否为当前登录用户
	if err := fc.CheckUserIdFromSession(userId); err != nil {
		fc.HandleErrCode(errcode.E.Base.ErrorMessage.WithMessage("用户检验失败"))
		return
	}
	response, err := fundService.BuildResponseForBalanceQuery(userId)
	if err != nil {
		fc.HandleErrCode(errcode.E.Internal.Internal.WithErr(err))
		return
	}
	fc.HandleBusinessObj(response)
}

// 查询用户余额充值记录
func (fc *FundController) BalanceChangeRecordQuery() {
	req := common.BalanceChangeRecordQueryRequest{}
	err := json.Unmarshal(fc.Ctx.Input.RequestBody, &req)
	if err != nil {
		fc.HandleErrCode(errcode.E.Base.RequestInvalid.WithErr(err))
		return
	}
	//校验是否为当前登录用户
	if err := fc.CheckUserIdFromSession(req.UserId); err != nil {
		fc.HandleErrCode(errcode.E.Base.ErrorMessage.WithMessage("用户检验失败"))
		return
	}
	response, err := fundService.BuildResponseForBalanceChangeRecordQuery(&req)
	if err != nil {
		fc.HandleErrCode(errcode.E.Internal.Internal.WithErr(err))
		return
	}
	fc.HandleBusinessObj(response)
}

// 查询用户授信额度
func (fc *FundController) CreditQuery() {
	userId := fc.Ctx.Input.Query("userId")
	//校验是否为当前登录用户
	if err := fc.CheckUserIdFromSession(userId); err != nil {
		fc.HandleErrCode(errcode.E.Base.ErrorMessage.WithMessage("用户检验失败"))
		return
	}
	response, err := fundService.BuildResposneForCreditQuery(userId)
	if err != nil {
		fc.HandleErrCode(errcode.E.Internal.Internal.WithErr(err))
		return
	}
	fc.HandleBusinessObj(response)
}

// 查询云上信用账户额度
func (fc *FundController) QueryCloudCreditCouponsTest() {
	userId := fc.Ctx.Input.Query("userId")
	response, err := fundService.GetCloudCreditCoupons([]string{userId})
	if err != nil {
		fc.HandleErrCode(errcode.E.Internal.Internal.WithErr(err))
		return
	}
	fc.HandleBusinessObj(response)
}

// adj_type = 1是增加,2是减少
// 调整云上信用账户额度
func (fc *FundController) AdjustCloudCreditTest() {
	userId := fc.Ctx.Input.Query("userId")
	adjustType := cast.ToInt32(fc.Ctx.Input.Query("adj_type"))
	amount := cast.ToFloat64(fc.Ctx.Input.Query("amount"))
	cloudUser, err := userService.GetCloudUserOne(userId)
	if err != nil {
		fc.HandleErrCode(errcode.E.Base.ErrorMessage.WithErr(err))
		return
	}
	err = fundService.AjudstCloudCredit(cloudUser.CloudId, adjustType, amount)
	if err != nil {
		fc.HandleErrCode(errcode.E.Internal.Internal.WithErr(err))
		return
	}
	fc.HandleBusinessSuccess()
}

// 查询调整云上信用账户额度记录
func (fc *FundController) QueryCloudCreditRecordTest() {
	userId := fc.Ctx.Input.Query("userId")
	offset := cast.ToInt32(fc.Ctx.Input.Query("offset"))
	limit := cast.ToInt32(fc.Ctx.Input.Query("limit"))
	cloudUser, err := userService.GetCloudUserOne(userId)
	if err != nil {
		fc.HandleErrCode(errcode.E.Base.ErrorMessage.WithErr(err))
		return
	}
	record, err := fundService.QueryCloudCreditRecord(userId, cloudUser.CloudId, offset, limit)
	if err != nil {
		fc.HandleErrCode(errcode.E.Internal.Internal.WithErr(err))
		return
	}
	fc.HandleBusinessObj(record)
}
